/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bgu.dcr.tp.impl;

import bgu.dcr.tp.api.Behavior;
import bgu.dcr.tp.api.World;
import bgu.dcr.tp.utils.EventListeners;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author not Shl
 */
public class BaseWorld implements World {

    private Map<Class, Map<Integer, Object>> database = new HashMap<>();
    private static final int SERVICES_ID = -1234;
    private List<Behavior> behaviors = new LinkedList<>();
    private Set<Integer> ids = new HashSet<>();
    private EventListeners<WorldListener> listeners = EventListeners.create(WorldListener.class);

    @Override
    public void addData(int index, Object data) {
        Class<? extends Object> dataclass = data.getClass();
        Map<Integer, Object> classDB = database.get(dataclass);
        if (classDB == null) {
            classDB = new HashMap<>();
            database.put(dataclass, classDB);
        }

        classDB.put(index, data);
        if (index != SERVICES_ID) {
            listeners.fire().onDataAdded(this, index, data);
            if (ids.add(index)) {
                listeners.fire().onIndexAdded(this, index);
            }
        }
    }

    @Override
    public void addService(Object data) {
        addData(SERVICES_ID, data);
    }

    @Override
    public Collection<Behavior> getBehaviors() {
        return behaviors;
    }

    @Override
    public void addBehavior(Behavior behavior) {
        behaviors.add(behavior);
        listeners.fire().onBehaviorAdded(this, behavior);
    }

    @Override
    public void removeBehavior(Behavior behavior) {
        behaviors.remove(behavior);
        listeners.fire().onBehaviorRemoved(this, behavior);
    }

    @Override
    public <T> T getData(int index, Class<T> type) {
        Map<Integer, Object> classDB = database.get(type);

        return (T) (classDB == null ? null : classDB.get(index));
    }

    @Override
    public <T> T getService(Class<T> type) {
        return getData(SERVICES_ID, type);
    }

    @Override
    public Collection<Integer> getAllIds() {
        return ids;
    }

    @Override
    public EventListeners<WorldListener> getListeners() {
        return listeners;
    }
}
